package com.wy.panda.config;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;

import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionManager;
import org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration;
import org.springframework.transaction.interceptor.TransactionInterceptor;

/**
 * 平台本地事务配置。<br/>
 * 不推荐使用{@link @Transactional}，<br/>
 * 配置比较分散，无法全局统一；<br/>
 * 也不利于强制服务方法的命名统一规范；<br/>
 * 如果需要使用，请使用注释{@link @EnableTransactionManagement}配置本配置类
 *
 * @author WangYuan
 * @since 2020年8月1日 下午4:46:19
 */
@Configuration
@ConditionalOnClass(value = {DataSource.class})
public class TransactionConfig extends ProxyTransactionManagementConfiguration {
	
	/**
	 * 本地事务相关属性配置
	 */
	private static Map<String, String> attributes = new LinkedHashMap<>();
	
    static {
        //可修改
    	attributes.put("save*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-Exception");
        attributes.put("insert*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-Exception");
        
        attributes.put("remove*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-Exception");
        attributes.put("delete*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-Exception");
        
        attributes.put("update*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-Exception");
        
        attributes.put("do*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-Exception");
        attributes.put("deal*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-Exception");
        
        //只读
        attributes.put("select*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly,-Exception");//分页查询的方法开头
        attributes.put("get*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly,-Exception");//返回单个值的方法开头
        attributes.put("list*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly,-Exception");//返回多个值的方法开头
        attributes.put("count*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly,-Exception");//统计方法开头
        attributes.put("*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly,-Exception");
    }
	
	@Bean("transactionManager")
	@ConditionalOnMissingBean
    public PlatformTransactionManager transactionManager(DataSource dataSource){
        return new DataSourceTransactionManager(dataSource);
    }
	
	@Bean("transactionPointcut")
    public AspectJExpressionPointcut aspectJExpressionPointcut(){
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression("execution (* com.wy.panda.service..*.*(..))");
        return pointcut;
    }
 
    @Bean("transactionPointcutAdvisor")
    public DefaultPointcutAdvisor defaultPointcutAdvisor(@Qualifier("transactionPointcut") AspectJExpressionPointcut pointcut, 
            @Qualifier("transactionInterceptor") TransactionInterceptor advice){
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
        advisor.setPointcut(pointcut);
        advisor.setAdvice(advice);
        advisor.setOrder(0);
        return advisor;
    }
    
	@Autowired
	private TransactionInterceptor transactionInterceptor;
	
	@Autowired
	private TransactionManager transactionManager;

	@PostConstruct
	public void init() {
		transactionInterceptor.setTransactionManager(transactionManager);
		
		Properties transactionAttributes = new Properties();
        for(Entry<String, String> item : attributes.entrySet()){
            transactionAttributes.put(item.getKey(), item.getValue());
        }
        transactionInterceptor.setTransactionAttributes(transactionAttributes);
	}
}
